package org.metasketch.diagram.javafx.graphics;

import java.util.ArrayList;
import java.util.List;

import javafx.event.EventTarget;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;

import org.metasketch.editor.links.ILinkConfig;
import org.metasketch.editor.links.LineSection;
import org.metasketch.editor.links.LinkEndCalculator;
import org.metasketch.editor.links.LinkEndOrientation;
import org.metasketch.editor.timeline.SnapshotManager;
import org.metasketch.graphics.GraphicLink;
import org.metasketch.graphics.Point;
import org.metasketch.javafx.graphics.JFXDiagram;
import org.metasketch.model.CommonIdentified;
import org.metasketch.model.ModelChangeManager;

public class DefaultLink extends BaseLink {

	protected List<PositionedLabel> labels = new ArrayList<PositionedLabel>();

	protected ILinkConfig linkConfig;
	protected LinkEndOrientation sourceOrientation;
	protected LinkEndOrientation targetOrientation;

	// protected Node sourceEnd;
	// protected Node targetEnd;

	public DefaultLink() {
		super(new GraphicLink());
		// line.setStyle("-fx-stroke: black; -fx-stroke-width: 3;   -fx-stroke-line-cap: butt;");
	}

	@Override
	protected void continueSetup() {
		// TODO Auto-generated method stub
		System.out.println("setting up default link");

		// String sourceGraphicType = null;
		// String targetGraphicType = null;
		//
		// if (source != null)
		// sourceGraphicType = source.getGraphicNode().getType();
		//
		// if (target != null)
		// targetGraphicType = target.getGraphicNode().getType();

		linkConfig = link.getLinkConfig(source, target);

		if (linkConfig != null) {

			sourceOrientation = linkConfig.getSource().getLinkEnd()
					.getOrientation();

			targetOrientation = linkConfig.getTarget().getLinkEnd()
					.getOrientation();

		}

		if (source != null)
			source.registerLink(this);

		if (target != null)
			target.registerLink(this);

		refreshModelGraphic();
		refreshLineDecorations();

	}

	@Override
	protected void refreshModelGraphic() {
		boolean selected = isSelected();
		setSelected(false);

		getChildren().clear();
		lines.clear();

		List<Point> points = graphicLink.getPoints();
		for (int i = 0; i < points.size() - 1; i++) {

			Point start = points.get(i);
			Point finish = points.get(i + 1);

			LineSection line = new LineSection(this);
			if (link.getStyle() == null)
				line.setStyle("-fx-stroke: black; -fx-stroke-width: 3;   -fx-stroke-line-cap: butt;");
			else
				line.setStyle(link.getStyle());

			line.setStartX(start.getX());
			line.setStartY(start.getY());

			line.setEndX(finish.getX());
			line.setEndY(finish.getY());

			line.setStart(start);
			line.setFinish(finish);

			line.setOnMouseClicked(this);

			lines.add(line);

		}

		if (source != null) {
			LineSection first = getFirstSection();
			first.setSourceObject(source);
		}

		if (target != null) {
			LineSection last = getLastSection();
			last.setTargetObject(target);
		}

		getChildren().addAll(lines);

		LinkEndBuilder.buildEnds(this);

		// toBack();
		// add labels
		List<CustomLabel> cLabels = new ArrayList<CustomLabel>();
		for (PositionedLabel label : labels) {
			cLabels.add(label.getLabel());
		}
		getChildren().addAll(cLabels);

		refreshSource();
		refreshTarget();

		setSelected(selected);
	}

	@Override
	public void handle(MouseEvent event) {

		Object source = event.getSource();

		System.out.println("Default Link: " + event);

		// String graphicType;
		if (event.getEventType() == MouseEvent.MOUSE_CLICKED
				&& event.getButton() == MouseButton.PRIMARY) {

			if (isSelected() && event.isControlDown()) {

				if (source instanceof LineControlPoint) {
					removeControlPoint((LineControlPoint) source);
					event.consume();
				} else {
					addControlPoint((LineSection) source, event);
					event.consume();
				}

			} else if (source instanceof LineSection) {
				setSelected(!isSelected());
				event.consume();
			} else if (source instanceof LineControlPoint) {
				SnapshotManager.takeSnapshot();
				event.consume();
			}

			// event.consume();
			// }
			// else if (event.getEventType() == MouseEvent.MOUSE_CLICKED
			// && event.getButton() == MouseButton.PRIMARY) {
			//
			// // source = event.getTarget();
			//
			//
		}
	}

	private void addControlPoint(LineSection source, MouseEvent event) {

		Point point = new Point((int) event.getX(), (int) event.getY());

		Point startPoint = source.getStart();
		int index = graphicLink.getPoints().indexOf(startPoint);

		graphicLink.getPoints().add(index + 1, point);

		refreshModelGraphic();
		refreshLineDecorations();

		SnapshotManager.takeSnapshot();

	}

	private void removeControlPoint(LineControlPoint source) {
		Point point = source.getControlPoint();

		// can't delete first nor last point !!!
		if (graphicLink.getPoints().indexOf(point) == 0
				|| graphicLink.getPoints().indexOf(point) == graphicLink
						.getPoints().size() - 1)
			return;

		graphicLink.getPoints().remove(point);

		refreshModelGraphic();
		refreshLineDecorations();

		SnapshotManager.takeSnapshot();

	}

	public void refresh(BaseGraphic baseGraphic) {

		// if (source == baseGraphic) {
		refreshSource();

		// } else if (target == baseGraphic) {
		refreshTarget();

		// }
		refreshLineDecorations();
	}

	public void refreshTarget() {
		if (target == null)
			return;

		LineSection section = getLastSection();

		Point point = LinkEndCalculator.getCoordinates(section.getStartX(),
				section.getStartY(), target, targetOrientation);
		int x = point.getX();
		int y = point.getY();

		section.changeFinish(x, y);

		// refreshDecorations();
	}

	public void refreshSource() {
		if (source == null)
			return;

		LineSection section = getFirstSection();

		Point point = LinkEndCalculator.getCoordinates(section.getEndX(),
				section.getEndY(), source, sourceOrientation);
		int x = point.getX();
		int y = point.getY();

		section.changeStart(x, y);

		// refreshDecorations();
	}

	public void refreshLineDecorations() {
		for (PositionedLabel label : labels) {
			label.positionLabel(this, lines);
		}

	}

	public ILinkConfig getLinkConfig() {
		return linkConfig;
	}

	@Override
	public void relatedModelChanges() {
		refreshModelGraphic();

	}

	public void removeFromDiagram() {
		JFXDiagram diagram = getDiagram();

		diagram.getDiagram().getGraphics().remove(graphicLink);
		diagram.removeNode(this);

		// remove from target and source graphics..

		if (source != null)
			source.unregisterLink(this);

		if (target != null)
			target.unregisterLink(this);

		diagram.getLinks().getChildren().remove(this);

	}

}
